﻿#region Using Directives

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using Kongo.Properties;

#endregion Using Directives


namespace Kongo.Tags
{
    internal class ForTag : BaseTag
    {
        #region Fields

        private bool capture;
        private List<Node> nodes;
        private Variable variable;
        private string itemName;

        #endregion Fields


        #region Methods

        public override bool ChildNode(Node node)
        {
            if (capture)
            {
                // Look for an end tag
                BaseTag bt = node as BaseTag;
                if (bt != null && (bt.Args[0] == "end" || bt.Args[0] == "endfor"))
                    capture = false; // Stop capturing (and don't bother keeping the end tag)
                else
                    nodes.Add(node);

                return true;
            }

            return false;
        }


        public override void Render(Context context, TextWriter output)
        {
            // Get the varible
            object var;
            if (!variable.TryEvaluate(context, out var) || var == null)
            {
                base.Render(context, output);
                return;
            }

            // Convert it to a list
            IList list = Helpers.ConvertToList(var);
            if (list == null)
                throw new ArgumentException(Helpers.Format(Resource.Argument_IncompatibleType, variable));

            // Create the forloop object
            ForLoop forloop = new ForLoop();
            object parentloop;
            if (context.TryGetValue("forloop", out parentloop))
                forloop.parentloop = (ForLoop)parentloop;

            // Do the loop
            context.Push();
            context["forloop"] = forloop;
            for (int i = 0; i < list.Count; i++)
            {
                context[itemName] = list[i];
                forloop.counter0 = i;
                forloop.counter = i + 1;
                forloop.revcounter = list.Count - i;
                forloop.revcounter0 = list.Count - i - 1;
                forloop.first = (i == 0);
                forloop.last = (i == list.Count - 1);

                // Render
                foreach (Node n in nodes)
                    n.Render(context, output);
            }
            context.Pop();
        }

        #endregion Methods


        #region Properties

        public override bool SupportsChildNodes
        {
            get { return true; }
        }

        #endregion Properties


        #region Constructors

        public ForTag(string[] args) : base(args)
        {
            // Should have exactly 4 arguments
            if (args.Length != 4)
                throw CreateSyntaxException();

            // Look for the 'in' keyword
            if (args[2] != "in")
                throw CreateSyntaxException();

            this.itemName = args[1];
            this.variable = new Variable(args[3]);

            this.nodes = new List<Node>();
            this.capture = true;
        }

        #endregion Constructors


        #region Types

        private class ForLoop
        {
            public int counter;
            public int counter0;
            public int revcounter;
            public int revcounter0;
            public bool first;
            public bool last;
            public ForLoop parentloop;
        }

        public class ForTagCreator : ITagCreator
        {
            #region Methods

            public Tag Create(string[] args)
            {
                return new ForTag(args);
            }

            #endregion Methods
        }

        #endregion Types
    }
}
